package com.atguigu.gmall.order.receiver;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.rabbit.config.MqConst;
import com.atguigu.gmall.enums.model.OrderStatus;
import com.atguigu.gmall.enums.model.ProcessStatus;
import com.atguigu.gmall.order.model.OrderInfo;
import com.atguigu.gmall.order.service.OrderInfoService;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: atguigu
 * @create: 2023-05-09 14:19
 */
@Slf4j
@Component
public class OrderReceiver {

    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 监听处理延迟关闭订单消息
     *
     * @param orderId
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(queues = MqConst.QUEUE_ORDER_CANCEL)
    public void processOrderClose(Long orderId, Channel channel, Message message) {
        if (orderId != null) {
            log.info("[订单服务]监听关单消息,数据:{}", orderId);
            //调用业务层关闭订单
            OrderInfo orderInfo = orderInfoService.getById(orderId);
            //判断订单状态只有 未支付订单 才会进行关闭
            if (orderInfo != null
                    && OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus())
                    && OrderStatus.UNPAID.name().equals(orderInfo.getProcessStatus())) {
                orderInfoService.execExpiredOrder(orderId);
            }
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }


    /**
     * 监听用户支付成功消息,修改订单状态,发送锁定锁定库存消息到库存服务
     *
     * @param orderId 订单ID
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_PAYMENT_PAY, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_PAYMENT_PAY, durable = "true"),
            key = MqConst.ROUTING_PAYMENT_PAY
    ))
    public void processPaySuccessResult(Long orderId, Channel channel, Message message) {
        try {
            if (orderId != null) {
                log.info("[订单服务]监听用户支付成功消息,订单ID:{}", orderId);
                //保证消费者业务幂等性-业务只处理一次即可
                String key = "order:" + orderId + ":stockrecord";
                Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, null, 1, TimeUnit.HOURS);
                if (flag) {
                    //1.根据订单ID查询订单记录
                    OrderInfo orderInfo = orderInfoService.getOrderInfoById(orderId);
                    if (orderInfo != null ) {
                        // && ProcessStatus.UNPAID.name().equals(orderInfo.getOrderStatus())
                        //2.更新订单支付状态:已支付
                        orderInfoService.updateOrderStatus(orderId, ProcessStatus.PAID);
                        //3.todo 发送消息到第三方库存系统 完成锁定 商品库存
                        orderInfoService.sendDeductLockMsg(orderId);
                    }
                }
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            //TODO 重新入队,让MQ服务器再次投递消息 做好最大次数限制,做好幂等性处理
            log.error("[订单服务]监听用户支付成功消息,处理失败:{}", e);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }


    /**
     * 监听库存系统 锁定商品库存结果
     *
     * @param deductResultJsonStr "{orderId:101,status:'DEDUCTED|OUT_OF_STOCK'}"
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_WARE_ORDER, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_WARE_ORDER, durable = "true"),
            key = MqConst.ROUTING_WARE_ORDER
    ))
    public void processDeductResult(String deductResultJsonStr, Channel channel, Message message) {
        try {
            if (StringUtils.isNotBlank(deductResultJsonStr)) {
                log.info("[订单服务]监听锁定库存结果:{}", deductResultJsonStr);
                //1.根据锁定库存结果 更新订单状态
                Map<String, String> map = JSON.parseObject(deductResultJsonStr, Map.class);
                String orderId = map.get("orderId");
                String status = map.get("status");
                if (StringUtils.isNotBlank(orderId) && StringUtils.isNotBlank(status)) {
                    if ("DEDUCTED".equals(status)) {
                        //将订单处理状态修改为"待发货"
                        orderInfoService.updateOrderStatus(Long.valueOf(orderId), ProcessStatus.WAITING_DELEVER);
                    }
                    if ("OUT_OF_STOCK".equals(status)) {
                        //将订单处理状态修改为"库存异常"
                        orderInfoService.updateOrderStatus(Long.valueOf(orderId), ProcessStatus.STOCK_EXCEPTION);
                    }
                }
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("[订单服务]监听锁定库存结果异常:{},消息内容:{}", e, deductResultJsonStr);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }

}
